package com.zkyc.framework.user.service.impl;

import com.alibaba.nacos.client.naming.utils.CollectionUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.zkyc.framework.common.constant.Constant;
import com.zkyc.framework.common.dto.PageDto;
import com.zkyc.framework.common.exception.ResultCode;
import com.zkyc.framework.common.mapper.*;
import com.zkyc.framework.common.pojo.*;
import com.zkyc.framework.common.vo.ResultVO;
import com.zkyc.framework.common.vo.role.RolePageDto;
import com.zkyc.framework.common.vo.role.RoleRightVo;
import com.zkyc.framework.common.vo.role.RoleVo;
import com.zkyc.framework.common.vo.role.RoleWebsiteVo;
import com.zkyc.framework.common.vo.user.RightVo;
import com.zkyc.framework.common.vo.website.WebsiteVo;
import com.zkyc.framework.user.Util.TokenUserUtil;
import com.zkyc.framework.user.service.RoleService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * (Role)表服务实现类
 *
 * @author wj
 * @since 2022-05-25 16:19:50
 */
@Service("roleService")
public class RoleServiceImpl implements RoleService {
    @Resource
    private RoleMapper roleMapper;

    @Autowired
    private RightMapper rightMapper;

    @Autowired
    private WebsiteMapper websiteMapper;

    @Autowired
    private WebsiteRefRoleMapper websiteRefRoleMapper;

    @Autowired
    private RoleRefRightMapper roleRefRightMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private WebRefRightMapper webRefRightMapper;

    @Autowired
    private MenuMapper menuMapper;

    @Autowired
    private RoleRefMenuMapper roleRefMenuMapper;

    @Autowired
    private UserRefRoleMapper userRefRoleMapper;

    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */
    @Override
    public Role queryById(Integer id) {
        return this.roleMapper.selectById(id);
    }

    @Override
    public ResultVO getRoleList(RolePageDto rolePageDto) {
        if (rolePageDto == null) {
            return ResultVO.fail(ResultCode.PARAM_INVALID);
        }
        //分页参数校验
        PageDto pageDto = new PageDto();
        BeanUtils.copyProperties(rolePageDto, pageDto);
        pageDto.checkParam();
        Page page = new Page(pageDto.getPage(), pageDto.getSize());
        Page<Role> roleList;
        if (Constant.SUPERADMINUSERID.equals(rolePageDto.getUserId())) {
            roleList = roleMapper.selectPage(page, new QueryWrapper<Role>().orderByDesc("gmt_updated"));
        } else {
            roleList = roleMapper.queryRoleListByUserId(rolePageDto.getUserId(), page);
        }
        return ResultVO.data(roleList);
    }

    /**
     * 新增数据
     *
     * @return 实例对象
     */
    @Override
    @Transactional
    public ResultVO insert(RoleWebsiteVo roleWebsiteVo) {
        if (roleWebsiteVo == null) {
            return ResultVO.fail(ResultCode.PARAM_INVALID);
        }
        Website website = websiteMapper.selectOne(new QueryWrapper<Website>().eq("id", roleWebsiteVo.getWebsiteId()));
        if (website == null) {
            return ResultVO.fail(ResultCode.SERVE_ERROR);
        }
        //如果角色已存在,返回错误信息
        List<Role> roleList = roleMapper.selectList(new QueryWrapper<Role>().eq("role_name", website.getWebsiteName() + "-" + roleWebsiteVo.getRoleName()));
        if (!CollectionUtils.isEmpty(roleList)) {
            return ResultVO.fail(503, "该角色已存在,请修改");
        }
        Role role = new Role();
        role.setRoleName(website.getWebsiteName() + "-" + roleWebsiteVo.getRoleName());
        String currentUserId = TokenUserUtil.getCurrentUserId();
        role.setCreatorName(userMapper.selectById(currentUserId).getUsername());
        role.setRoleDescription(roleWebsiteVo.getRoleDescription());
        role.setGmtCreated(new Date());
        role.setGmtUpdated(new Date());
        role.setRoleType(1);
        role.setStatus(1);
        role.setIsDeleted(0);
        roleMapper.insert(role);

        WebsiteRefRole websiteRefRole = new WebsiteRefRole();
        websiteRefRole.setWebsiteId(roleWebsiteVo.getWebsiteId());
        websiteRefRole.setRoleId(role.getId());
        websiteRefRole.setGmtCreated(new Date());
        websiteRefRoleMapper.insert(websiteRefRole);
        roleWebsiteVo.getRightIdList().forEach(s -> {
                    RoleRefRight roleRefRight = new RoleRefRight();
                    roleRefRight.setRoleId(role.getId());
                    roleRefRight.setRightId(s);
                    roleRefRight.setGmtCreated(new Date());
                    roleRefRightMapper.insert(roleRefRight);
                }
        );
        roleWebsiteVo.getMenuIdList().forEach(s -> {
            RoleRefMenu roleRefMenu = new RoleRefMenu();
            roleRefMenu.setRoleId(role.getId());
            roleRefMenu.setMenuId(s);
            roleRefMenu.setUpdateTime(new Date());
            roleRefMenuMapper.insert(roleRefMenu);
        });
        return ResultVO.success(ResultCode.SUCCESS);
    }

    /**
     * 更新角色
     *
     * @return 实例对象
     */
    @Override
    public ResultVO update(RoleWebsiteVo roleWebsiteVo) {
        if (roleWebsiteVo == null) {
            return ResultVO.fail(ResultCode.PARAM_INVALID);
        }
        Role role = queryById(roleWebsiteVo.getId());
        if (role == null) {
            return ResultVO.fail(ResultCode.SERVE_ERROR);
        }
        roleRefRightMapper.delete(new QueryWrapper<RoleRefRight>().eq("role_id", roleWebsiteVo.getId()));
        websiteRefRoleMapper.delete(new QueryWrapper<WebsiteRefRole>().eq("role_id", roleWebsiteVo.getId()));
        roleRefMenuMapper.delete(new QueryWrapper<RoleRefMenu>().eq("role_id", roleWebsiteVo.getId()));
        Role role1 = new Role();
        BeanUtils.copyProperties(roleWebsiteVo, role1);
        role1.setGmtUpdated(new Date());
        roleMapper.updateById(role1);

        WebsiteRefRole websiteRefRole = new WebsiteRefRole();
        websiteRefRole.setWebsiteId(roleWebsiteVo.getWebsiteId());
        websiteRefRole.setRoleId(role.getId());
        websiteRefRole.setGmtCreated(new Date());
        websiteRefRoleMapper.insert(websiteRefRole);
        roleWebsiteVo.getRightIdList().forEach(s -> {
                    RoleRefRight roleRefRight = new RoleRefRight();
                    roleRefRight.setRoleId(role.getId());
                    roleRefRight.setRightId(s);
                    roleRefRight.setGmtCreated(new Date());
                    roleRefRightMapper.insert(roleRefRight);
                }
        );
        roleWebsiteVo.getMenuIdList().forEach(s -> {
                    RoleRefMenu roleRefMenu = new RoleRefMenu();
                    roleRefMenu.setRoleId(role.getId());
                    roleRefMenu.setMenuId(s);
                    roleRefMenu.setUpdateTime(new Date());
                    roleRefMenuMapper.insert(roleRefMenu);
                }
        );
        return ResultVO.success(ResultCode.SUCCESS);
    }

    /**
     * 通过主键删除数据
     *
     * @param id 主键
     * @return 是否成功
     */
    @Override
    public ResultVO deleteById(Integer id) {
        if (id == null) {
            return ResultVO.fail(ResultCode.PARAM_INVALID);
        }
        if (queryById(id) == null) {
            return ResultVO.fail(ResultCode.SERVE_ERROR);
        }
        roleMapper.deleteById(id);
        return ResultVO.success(ResultCode.SUCCESS);
    }


    //获取用户权限列表
    public List<RightVo> getAuthorization(List<Integer> roleIdList) {
        List<RightVo> rightVoList = new LinkedList<>();
        Set<Right> rightVoSet = new HashSet<>();
        List<Right> rightAllList = new ArrayList<>();
        roleIdList.forEach(s -> {
            //根据用户id查询权限列表
            List<Right> rightByRoleId = rightMapper.getRightListByRoleId(s.longValue());
            rightAllList.addAll(rightByRoleId);
            rightVoSet.addAll(rightByRoleId);
        });
        Set<String> parentSet = rightVoSet.stream().map(Right::getRightParent).collect(Collectors.toSet());
        ArrayList<String> parentArray = new ArrayList<>(parentSet);
        for (String s : parentArray) {
            RightVo rightVo = new RightVo();
            rightVo.setName(s);
            HashSet childSet = new HashSet();
            for (Right right : rightAllList) {
                if (right.getRightParent().equals(s)) {
                    childSet.add(right);
                    rightVo.setMaxSort(right.getSort());
                }
            }
            rightVo.setChildRights(childSet);
            rightVoList.add(rightVo);
        }
        return rightVoList.stream().sorted(Comparator.comparing(RightVo::getMaxSort)).collect(Collectors.toList());
    }


    /**
     * 角色的启用与禁用
     *
     * @param roleId
     * @param type
     * @return
     */
    @Override
    public ResultVO forbidden(Integer roleId, Integer type) {
        if (roleId == null && type == null) {
            return ResultVO.fail(ResultCode.PARAM_INVALID);
        }
        Role role = queryById(roleId);
        role.setStatus(type);
        roleMapper.update(role, new QueryWrapper<Role>().eq("id", roleId));
        return ResultVO.success(ResultCode.SUCCESS);
    }

    //查看角色信息
    @Override
    public ResultVO queryRoleInfo(Integer roleId) {
        if (roleId == null) {
            return ResultVO.fail(ResultCode.PARAM_INVALID);
        }
        RoleRightVo roleRightVo = new RoleRightVo();
        Role role = queryById(roleId);
        Website website = websiteMapper.getWebsiteByRoleId(roleId);
        if (website == null) {
            return ResultVO.fail(ResultCode.PARAM_INVALID);
        }
        roleRightVo.setWebsiteId(website.getId());
        roleRightVo.setRoleName(role.getRoleName());
        roleRightVo.setWebsiteName(website.getWebsiteName());
        List<Integer> rightIdList = roleRefRightMapper.selectList(new QueryWrapper<RoleRefRight>().eq("role_id", roleId)).stream().map(RoleRefRight::getRightId).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(rightIdList)) {
            return ResultVO.fail(500, "该角色未拥有权限");
        }
        List<Right> rightList = rightMapper.selectBatchIds(rightIdList);
        String rightString = rightList.stream().map(Right::getName).collect(Collectors.joining(","));
        roleRightVo.setRightString(rightString);
        roleRightVo.setRightIdList(rightIdList);
        return ResultVO.data(roleRightVo);
    }

    @Override
    public ResultVO queryWebsiteList(String userId) {
        if (userId == null) {
            return ResultVO.fail(ResultCode.PARAM_INVALID);
        }
        List<Website> websiteList;
        if (Constant.SUPERADMINUSERID.equals(userId)) {
            websiteList = websiteMapper.selectList(null);
        } else {
            websiteList = roleMapper.queryWebsiteListByUserId(userId);
        }
        return ResultVO.data(websiteList);
    }


    @Override
    public ResultVO queryWebsiteRight(Integer websiteId) {
        if (websiteId == null) {
            return ResultVO.fail(ResultCode.PARAM_INVALID);
        }
        Website website = websiteMapper.selectById(websiteId);
        List<WebRefRight> webRefRightList = webRefRightMapper.selectList(new QueryWrapper<WebRefRight>().eq("website_url", website.getWebsiteUrl()));
        List<Integer> rightIdList = webRefRightList.stream().map(WebRefRight::getRightId).collect(Collectors.toList());
        List<Right> rights = rightMapper.selectBatchIds(rightIdList);
        //只有之江实验室官网需要稿件管理,其他的都去除
        Iterator<Right> iterator = rights.iterator();
        while (iterator.hasNext()) {
            Right next = iterator.next();
            String name = next.getName();
            if (websiteId != 1 && name.equals("稿件管理")) {
                iterator.remove();
            }
            if (websiteId == 4 && name.equals("组织管理")) {
                iterator.remove();
            }
        }
        List<Right> rightTree = getRightTree(rights);
        return ResultVO.data(rightTree);
    }


    /**
     * 新增用户时,查询出该用户具有的角色列表
     *
     * @param userId
     * @return
     */
    @Override
    public ResultVO queryAllRoleListByUserId(String userId) {
        List<Role> roles;
        if (Constant.SUPERADMINUSERID.equals(userId)) {
            roles = roleMapper.selectList(null);
        } else {
            roles = roleMapper.queryAllRoleListByUserId(userId);
        }
        Set<WebsiteVo> websiteVos = new HashSet<>();
        Set<String> websiteNames = new HashSet<>();
        for (Role role : roles) {
            String[] split = role.getRoleName().split("-");
            websiteNames.add(split[0]);
        }
        for (String websiteName : websiteNames) {
            WebsiteVo websiteVo = new WebsiteVo();
            Website website = websiteMapper.selectOne(new QueryWrapper<Website>().eq("website_name", websiteName));
            if (website == null) {
                continue;
            }
            websiteVo.setWebsiteId(website.getId());
            websiteVo.setWebsiteName(websiteName);
            List<RoleVo> childRoles = new ArrayList<>();
            roles.forEach(a -> {
                if (websiteName.equals(a.getRoleName().split("-")[0])) {
                    RoleVo roleVo = new RoleVo();
                    roleVo.setRoleId(a.getId());
                    roleVo.setRoleName(a.getRoleName());
                    childRoles.add(roleVo);
                }
            });
            websiteVo.setRoleList(childRoles);
            websiteVos.add(websiteVo);
        }

        return ResultVO.data(websiteVos);
    }

    /**
     * 为站点赋予权限
     *
     * @param websiteId
     * @param websiteName
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public ResultVO addWebsiteRole(Integer websiteId, String websiteName, String userId) {
        if (websiteId == null) {
            return ResultVO.fail(ResultCode.PARAM_INVALID);
        }
        //为新建网站设置一个该网站的管理员
        String roleName = websiteName + "-管理员";
        //如果角色名已存在,返回错误信息
        Role role1 = roleMapper.selectOne(new QueryWrapper<Role>().eq("role_name", roleName));
        if (role1 != null) {
            return ResultVO.fail(503, "该角色已存在,请修改");
        }
        Role role = new Role();
        role.setRoleName(roleName);
        role.setCreatorName(userMapper.selectById(userId).getUsername());
        role.setRoleDescription(roleName);
        role.setGmtCreated(new Date());
        role.setGmtUpdated(new Date());
        role.setRoleType(0);
        role.setStatus(1);
        role.setIsDeleted(0);
        roleMapper.insert(role);
        //网站角色绑定
        WebsiteRefRole websiteRefRole1 = new WebsiteRefRole();
        websiteRefRole1.setWebsiteId(websiteId);
        websiteRefRole1.setRoleId(role.getId());
        websiteRefRole1.setGmtCreated(new Date());
        websiteRefRoleMapper.insert(websiteRefRole1);
        if (!Constant.SUPERADMINUSERID.equals(userId)){
            //角色用户绑定
            UserRefRole userRefRole = new UserRefRole();
            userRefRole.setRoleId(role.getId());
            userRefRole.setUserId(userId);
            userRefRoleMapper.insert(userRefRole);
        }
        String websiteUrl = websiteMapper.selectById(websiteId).getWebsiteUrl();
        List<WebRefRight> webRefRightList = webRefRightMapper.selectList(new QueryWrapper<WebRefRight>().eq("website_url", websiteUrl));
        if (CollectionUtils.isEmpty(webRefRightList)) {
            return ResultVO.fail(500, "新增失败,该网站未绑定权限.");
        }
        List<Integer> rightIds = webRefRightList.stream().map(WebRefRight::getRightId).collect(Collectors.toList());
        rightIds.forEach(s -> {
            RoleRefRight roleRefRight = new RoleRefRight();
            roleRefRight.setRoleId(role.getId());
            roleRefRight.setRightId(s);
            roleRefRight.setGmtCreated(new Date());
            roleRefRightMapper.insert(roleRefRight);
        });
        String rightListString = rightIds.stream().map(Objects::toString).collect(Collectors.joining(","));
        List<Menu> menuByRight = roleRefMenuMapper.getMenuByRight(rightListString);
        List<Integer> menuIdList = menuByRight.stream().map(Menu::getId).collect(Collectors.toList());
        menuIdList.forEach(s -> {
            RoleRefMenu roleRefMenu = new RoleRefMenu();
            roleRefMenu.setRoleId(role.getId());
            roleRefMenu.setMenuId(s);
            roleRefMenu.setUpdateTime(new Date());
            roleRefMenuMapper.insert(roleRefMenu);
        });
        return ResultVO.success("操作成功!");
    }

    @Override
    public ResultVO getTreeData() {

        //先查询出数据所有的标签数据列表
        List<Menu> Menus = menuMapper.selectList(new LambdaQueryWrapper<Menu>().ne(Menu::getIsDelete, 1));
        return getMenuTree(Menus);
    }

    public ResultVO getMenuTree(List<Menu> Menus) {
        //判断是否有数据
        if (!CollectionUtils.isEmpty(Menus)) {
            // 过滤所有的一级目录，父id为0
            List<Menu> firstMenu = Menus.stream().filter(c -> c.getParentId().toString().equals("0")).sorted(Comparator.comparing(Menu::getSort)).collect(Collectors.toList());

            //查出非一级目录，按照其父id分类
            Map<Integer, List<Menu>> collect = Menus.stream().filter(c -> !(c.getParentId().toString().equals("0"))).sorted(Comparator.comparing(Menu::getSort)).collect(Collectors.groupingBy(Menu::getParentId));

            for (Menu menu : firstMenu) {
                //如果一级目录的id中是否包含非一级目录的父id
                if (collect.get(menu.getId()) == null) {
                    //没有，说明不是该一级目录没有下一级目录，则将其子目录设为空
                    menu.setChildrenList(new ArrayList<>());
                } else {
                    //有，则说明有二级目录，将二级目录的的List集合，赋给子目录
                    menu.setChildrenList(collect.get(menu.getId()));

                    //构建三级树
                    //遍历二级目录，判断是否含有三级目录
                    collect.get(menu.getId()).forEach(b -> {
                        if (collect.get(b.getId()) == null) {
                            //没有，将二级目录下的三级目录设为空
                            b.setChildrenList(new ArrayList<>());
                        } else {
                            //有，将三级目录的List集合，赋给三级目录
                            b.setChildrenList(collect.get(b.getId()));
                        }

                    });
                }
            }
            //将firstMenu返回，前端可以通过遍历获取各级目录的数据从而形成三级树的效果
            return ResultVO.data(firstMenu);
        } else {
            return ResultVO.data(new ArrayList<>());
        }
    }

    @Override
    public ResultVO getRoleMenu(Integer roleId) {
        if (roleId == null) {
            return ResultVO.fail(ResultCode.PARAM_INVALID);
        }
        List<RoleRefMenu> roleRefMenus = roleRefMenuMapper.selectList(new LambdaQueryWrapper<RoleRefMenu>().eq(RoleRefMenu::getRoleId, roleId));
        if (CollectionUtils.isEmpty(roleRefMenus)) {
            return ResultVO.data(new ArrayList<>());
        }
        List<Integer> menuIdList = roleRefMenus.stream().map(RoleRefMenu::getMenuId).collect(Collectors.toList());
        List<Menu> menuList = menuMapper.selectBatchIds(menuIdList);
        return ResultVO.data(getMenuTree(menuList));
    }


    @Override
    public ResultVO getMenuByRight(List<Integer> rightIdList) {
        if (CollectionUtils.isEmpty(rightIdList)) {
            return null;
        } else {
            String rightListString = rightIdList.stream().map(Objects::toString).collect(Collectors.joining(","));
            List<Menu> menuByRight = roleRefMenuMapper.getMenuByRight(rightListString);
            return getMenuTree(menuByRight);
        }
    }

    @Override
    public String getDataRight(String websiteId, String userId) {
        String dataRight = StringPool.ZERO;
        if (Constant.SUPERADMINUSERID.equals(userId)) {
            dataRight = StringPool.ONE;
            return dataRight;
        }
        List<String> webSiteRoles = websiteRefRoleMapper.selectRoleList(websiteId);
        List<String> userRoles = userRefRoleMapper.selectRoleList(userId);
        userRoles.retainAll(webSiteRoles);
        for (String roleId : userRoles) {
            Role role = roleMapper.selectById(roleId);
            if (StringPool.ONE.equals(role.getDataRight() + "")) {
                dataRight = StringPool.ONE;
                return dataRight;
            }
        }
        return dataRight;
    }


    /**
     * stream方法转换成树形结构
     *
     * @param rightList
     * @return
     */
    public static List<Right> getRightTree(List<Right> rightList) {
        return rightList.stream()
                // 筛选出父节点
                .filter(t -> t.getParentId() == 0)
                // 设置父节点的子节点列表
                .peek(item -> item.setChildRights(streamGetChildren(item, rightList)))
                .collect(Collectors.toList());
    }

    /**
     * stream 方式递归查找子节点列表
     * @return rightList
     */
    public static List<Right> streamGetChildren(Right right, List<Right> rightList) {
        return rightList.stream()
                .filter(t -> t.getParentId().equals(right.getId()))
                .peek(item -> item.setChildRights(streamGetChildren(item, rightList)))
                .sorted(Comparator.comparing(Right::getSort))
                .collect(Collectors.toList());
    }
}